package com.dhms.uikit

import android.content.Context
import android.text.Editable
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener
import com.dhms.uikit.databinding.DialogViewBinding
import com.google.android.material.dialog.MaterialAlertDialogBuilder

/**
 * A dialog builder with the custom view.
 */
class DialogBuilder : MaterialAlertDialogBuilder {

    private var _binding: DialogViewBinding? = null
    val binding get() = _binding!!

    private var onPositiveButtonClickLister: (() -> Boolean)? = null
    private var onNegativeButtonClickLister: (() -> Boolean)? = null

    private var inputLayoutValidationRules: List<Regex>? = null

    constructor(context: Context) : super(context, R.style.Theme_UiKit_Dialog) {
        init()
    }

    constructor(context: Context, overrideThemeResId: Int) : super(context, overrideThemeResId) {
        init()
    }

    private fun init() {
        _binding = DialogViewBinding.inflate(LayoutInflater.from(context))
        setView(binding.root)

        binding.progressValue = -1
    }

    /**
     * Sets whether the dialog is cancelable or not.  Default is true.
     *
     * @return This Builder object to allow for chaining of calls to set methods
     */
    fun setIsCancelable(cancelable: Boolean): DialogBuilder {
        super.setCancelable(cancelable)

        return this
    }

    /**
     * Sets the title of the dialog.
     *
     * @return This Builder object to allow for chaining of calls to set methods
     */
    fun setTitle(title: String): DialogBuilder {
        binding.title = title

        return this
    }

    /**
     * Sets the message of the dialog.
     *
     * @return This Builder object to allow for chaining of calls to set methods
     */
    fun setMessage(message: String): DialogBuilder {
        binding.message = message

        return this
    }

    /**
     * Sets whether the dialog has a input box or not.
     *
     * @return This Builder object to allow for chaining of calls to set methods
     */
    fun setEditable(
        text: String? = null,
        hint: String? = null,
        helpText: String? = null,
        rules: List<Regex>? = null,
        onTextChangedListener: (
            text: Editable?
        ) -> Unit,
    ): DialogBuilder {
        if (text != null && hint != null) {
            throw Exception("Not support set origin text and hint meanwhile.")
        }
        binding.dialogInputWrapper.visibility = View.VISIBLE
        binding.dialogInputWrapper.helperText = helpText
        binding.dialogInput.addTextChangedListener {
            binding.dialogInputWrapper.error = null
            onTextChangedListener(it)
        }
        inputLayoutValidationRules = rules
        if (hint != null) {
            binding.dialogInputWrapper.hint = hint
            binding.dialogInput.setOnFocusChangeListener { _, hasFocus ->
                binding.dialogInputWrapper.hint = if (hasFocus) null else hint
            }
            return this
        }
        if (text != null) {
            binding.dialogInput.setText(text)
        }

        return this
    }

    /**
     * Sets the text and callback of the negative button.
     *
     * @return This Builder object to allow for chaining of calls to set methods
     */
    fun setOnNegativeButtonClickListener(
        t: String? = null,
        onClickListener: (() -> Boolean)? = null
    ): DialogBuilder {
        binding.dialogNegativeBtn.apply {
            visibility = View.VISIBLE
            onNegativeButtonClickLister = onClickListener
            if (t != null) {
                text = t
            }
        }

        return this
    }

    /**
     * Sets the text and callback of the positive button.
     *
     * @return This Builder object to allow for chaining of calls to set methods
     */
    fun setOnPositiveButtonClickListener(
        t: String? = null,
        onClickListener: (() -> Boolean)? = null,
    ): DialogBuilder {
        binding.dialogPositiveBtn.apply {
            visibility = View.VISIBLE
            onPositiveButtonClickLister = onClickListener
            if (t != null) {
                text = t
            }
        }

        return this
    }

    /**
     * Create the dialog.
     *
     * @return This Builder object to allow for chaining of calls to set methods
     */
    fun createDialog(): AlertDialog {
        val dialog = super.create()
        binding.dialogNegativeBtn.setOnClickListener {
            if ((onNegativeButtonClickLister != null && onNegativeButtonClickLister!!()) || onNegativeButtonClickLister == null) {
                dialog.dismiss()
            }
        }
        binding.dialogPositiveBtn.setOnClickListener {
            if (binding.dialogInputWrapper.isVisible && inputLayoutValidationRules != null) {
                var validationResult = false
                val inputText = binding.dialogInput.text.toString()
                inputLayoutValidationRules!!.forEach {
                    if (it.matches(inputText)) {
                        validationResult = true
                        return@forEach
                    }
                }
                if (!validationResult) {
                    binding.dialogInputWrapper.error = "输入值不合法，请重新输入！"
                    return@setOnClickListener
                }
            }

            if ((onPositiveButtonClickLister != null && onPositiveButtonClickLister!!()) || onPositiveButtonClickLister == null) {
                dialog.dismiss()
            }
        }
        return dialog
    }
}

fun DialogViewBinding.updateTitle(title: String) {
    this.title = title
}

fun DialogViewBinding.updateMessage(message: String) {
    this.message = message
}

fun DialogViewBinding.updateProgress(value: Int, tip: String? = null) {
    progressValue = value
    if (tip != null) {
        progressTip = tip
    }
}